package com.angel.resourceBundle.managers;

import java.io.Serializable;
import java.util.Collection;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.log4j.Logger;

import com.angel.common.helpers.StringHelper;
import com.angel.dao.generic.interfaces.GenericDAO;
import com.angel.resourceBundle.contexts.ComplexResourceBundleContext;
import com.angel.resourceBundle.contexts.ResourceBundleContext;
import com.angel.resourceBundle.daos.internationalizable.InternationalizableDAO;
import com.angel.resourceBundle.daos.internationalizer.InternationalizerDAO;
import com.angel.resourceBundle.daos.propertyValue.ComplexPropertyValueDAO;
import com.angel.resourceBundle.exceptions.ResourceBundleException;
import com.angel.resourceBundle.internationalizable.Internationalizable;
import com.angel.resourceBundle.internationalizer.Internationalizer;
import com.angel.resourceBundle.propertyValue.PropertyValue;
import com.angel.resourceBundle.propertyValue.impl.ComplexPropertyValue;
import com.angel.resourceBundle.results.PropertyValueResult;
import com.angel.resourceBundle.results.impl.PropertyValueResultImpl;
import com.angel.resourceBundle.transformers.PropertyValueToComplexPropertyValueTransformer;

/** {@link ComplexResourceBundleManager} helps you to internationalize all your business object needed to implements in differents languajes.
 * For this case you must create internationalizable and internationalizer objects (recomendally separate one objects from business object layer).
 * These objects have a relation one to one with property value. So a property value only has a internationalizable and internationalizer object.
 * Afterwards to implements a direct access, property values has a extended key which identifiers only one property value instance.
 * This extended key is generated with the internationalizable key and {@link ResourceBundleContext} class when its generateKey method
 *  (with internationalizer key by parameter) is called.
 *
 * Finally {@link ComplexResourceBundleManager} manipulate all {@link ComplexPropertyValueImpl} objects which helps you to internationalize objects
 * that only aren't strings (for example: labels, tittles, etc).
 *
 * @author William
 *
 */
public class ComplexResourceBundleManager extends ResourceBundleManager{

	private static final Logger LOGGER = Logger.getLogger(ComplexResourceBundleManager.class);

	private GenericDAO<Internationalizable, Serializable> internationalizableDAO;
	private GenericDAO<Internationalizer, Serializable> internationalizerDAO;

	public <T extends PropertyValue, Code extends Serializable> ComplexResourceBundleManager(ResourceBundleContext resourceBundleContext, GenericDAO<T, Code> propertyValueDAO) {
		super(resourceBundleContext, propertyValueDAO);
	}

	/** Register a property value for the context and it is registered with an internationalizable and an internationalizer objetcs.
	 *  The internationalizable key is the property value key.
	 *	Previously the internationalizable and internationalizer object must be persisted to it can register correctly a property value. To do it, must call to register Internationalzer or Internationalizable message.
	 * @throws ResourceBundleException
	 *
	 *
	 */
	public void registerPropertyValue(Internationalizable internationalizable, Internationalizer internationalizer) throws ResourceBundleException {
		String extendedKey = null;
		if(internationalizable != null && StringHelper.isNotEmpty(internationalizable.getKeyValue())){

			extendedKey = super.getResourceBundleContext().generateExtendedKey(internationalizable.getKeyValue(), internationalizer.getName());

			LOGGER.info("Registering property value with internationalizable [" + internationalizable.getKeyValue() + "] and internationalizer [" + internationalizer.getName() + "].");
			this.registerInternationalizable(internationalizable);

			this.registerInternationalizer(internationalizer);

			ComplexPropertyValue complexPropertyValue = (ComplexPropertyValue) this.createPropertyValueInstance();
			complexPropertyValue.setExtendedKey(extendedKey);
			complexPropertyValue.setInternationalizable(internationalizable);
			complexPropertyValue.setInternationalizer(internationalizer);

			LOGGER.info("Updating property value.");
			super.getResourceBundleContext().updatePropertyValue(complexPropertyValue);

			LOGGER.info("Registering property value [" + complexPropertyValue.getExtendedKey() + " = " + complexPropertyValue.getText() + "].");
			super.registerPropertyValue(complexPropertyValue);
		}
	}



	/** Register an internationalizable object. This message must be called before to register a property value with this internationalizable object.
	 *
	 * @param internationalizable
	 * @throws ResourceBundleObjectNotPersitedException
	 */
	public void registerInternationalizable(Internationalizable internationalizable) {
		this.getInternationalizableDAO().persist(internationalizable);
	}

	/** Register an internationalizer object. This message must be called before to register a property value with this internationalizer object.
	 *
	 * @param internationalizer
	 * @throws ResourceBundleObjectNotPersitedException
	 */
	public void registerInternationalizer(Internationalizer internationalizer) {
		this.getInternationalizerDAO().persist(internationalizer);
	}

	/**
	 * @return the internationalizableDAO
	 */
	@SuppressWarnings("unchecked")
	public <T extends Internationalizable, H extends Serializable> InternationalizableDAO<T, H> getInternationalizableDAO() {
		return (InternationalizableDAO<T, H>) internationalizableDAO;
	}

	/**
	 * @param internationalizableDAO the internationalizableDAO to set
	 */
	@SuppressWarnings("unchecked")
	public <T extends Internationalizable, H extends Serializable> void setInternationalizableDAO(InternationalizableDAO<T, H> internationalizableDAO) {
		this.internationalizableDAO = (GenericDAO<Internationalizable, Serializable>) internationalizableDAO;
	}

	/**
	 * @return the internationalizerDAO
	 */
	@SuppressWarnings("unchecked")
	public <T extends Internationalizer, H extends Serializable> InternationalizerDAO<T, H> getInternationalizerDAO() {
		return (InternationalizerDAO<T, H>) internationalizerDAO;
	}

	/**
	 * @param internationalizerDAO the internationalizerDAO to set
	 */
	@SuppressWarnings("unchecked")
	public <T extends Internationalizer, H extends Serializable> void setInternationalizerDAO(InternationalizerDAO<T, H> internationalizerDAO) {
		this.internationalizerDAO = (GenericDAO<Internationalizer, Serializable>) internationalizerDAO;
	}

	@Override
	protected PropertyValue createPropertyValueInstance() {
		return new ComplexPropertyValue();
	}

	public Collection<ComplexPropertyValue> findAllPropertyValuesFor(Internationalizer internationalizer) {
		ComplexPropertyValueDAO complexPropertyValueDAO = (ComplexPropertyValueDAO) super.getPropertyValueDAO(ComplexPropertyValue.class);
		Collection<ComplexPropertyValue> complexPropertieValues = complexPropertyValueDAO.findAllByInternationalizer(internationalizer);
		return CollectionUtils.transformedCollection(complexPropertieValues, new PropertyValueToComplexPropertyValueTransformer());
	}

	public PropertyValueResult findAllPropertyValuesWithResultFor(Internationalizer internationalizer) {
		String resourceBundleKey = super.getResourceBundleContext().generateResourceBundleContextKey();
		ComplexPropertyValueDAO complexPropertyValueDAO = (ComplexPropertyValueDAO) super.getPropertyValueDAO(ComplexPropertyValue.class);
		Collection<ComplexPropertyValue> complexPropertieValues = complexPropertyValueDAO.findAllByInternationalizer(internationalizer);
		return new PropertyValueResultImpl(complexPropertieValues,resourceBundleKey, super.getResourceBundleContext().getKeySeparator());
	}

	public void registerPropertyValue(Internationalizable internationalizable) throws ResourceBundleException {
		String extendedKey = null;
		if(internationalizable != null && StringHelper.isNotEmpty(internationalizable.getKeyValue())){
			ComplexResourceBundleContext complexResourceBundleContext = (ComplexResourceBundleContext) super.getResourceBundleContext();
			extendedKey = complexResourceBundleContext.generateExtendedKey(internationalizable.getKeyValue());

			this.registerInternationalizable(internationalizable);

			Internationalizer currentInternationalizer = complexResourceBundleContext.findCurrentInternationalizer();
			LOGGER.info("Registering property value with internationalizable [" + internationalizable.getKeyValue() + "] and current internationalizer [" + currentInternationalizer.getName() + "].");

			ComplexPropertyValue complexPropertyValue = (ComplexPropertyValue) this.createPropertyValueInstance();
			complexPropertyValue.setExtendedKey(extendedKey);
			complexPropertyValue.setInternationalizable(internationalizable);
			complexPropertyValue.setInternationalizer(currentInternationalizer);

			LOGGER.info("Updating property value.");
			super.getResourceBundleContext().updatePropertyValue(complexPropertyValue);

			LOGGER.info("Registering property value [" + complexPropertyValue.getExtendedKey() + " = " + complexPropertyValue.getText() + "].");
			super.registerPropertyValue(complexPropertyValue);
		}
	}
}
